#include "cgzCLua.h"
#include "cgzCTcpWS.h"
#include "cgzCThreadPool.h"

bool cgzCLua::runws(const cgzITask *iTask, cgzCLoopS *pnode)
{
    auto etype = pnode->getEType();
    switch (etype)
    {
    case TCPS_ACPT: // 连接成功
    {
        auto *acpts = static_cast<cgzCAcptS *>(pnode);
        ocall(iTask->m_tref, "accept", {iTask->getName(), acpts->m_ufd});
    }
    break;
    case TCPS_RECV: // 接收数据
    {
        auto *recvws = static_cast<cgzCRecvWS *>(pnode);
        switch (recvws->rt)
        {
        case WEBSOCKET_SEND_PING:
        {
            ocall(iTask->m_tref, "ping", {recvws->m_ufd});
        }
        break;
        case WEBSOCKET_SEND_PONG:
        {
            ocall(iTask->m_tref, "pong", {recvws->m_ufd});
        }
        break;
        case WEBSOCKET_SEND_TEXT:
        {
            ocall(iTask->m_tref, "recvt", {recvws->m_ufd, {recvws->m_data, (int)recvws->m_len}});
        }
        break;
        case WEBSOCKET_SEND_BINARY:
        {
            auto &header = *(cgzHeader *)(recvws->m_data);
            auto data = (const char *)(recvws->m_data + sizeof(cgzHeader));
            ocall(iTask->m_tref, "recvb", {
                recvws->m_ufd, 
                (int)header.mid, 
                {data, (int)header.len}, 
                (long)header.cid
            });
        }
        break;
        default:
        {
            cgz_this_error("task tcpWS :{} recvws type:{} not support", iTask->getName(), recvws->rt);
        }
        }
    }
    break;
    case TCPS_DISC: // 断开连接
    {
        auto *discws = static_cast<cgzCDiscS *>(pnode);
        ocall(iTask->m_tref, "disc", {discws->m_ufd});
    }
    break;
    default:
    {
        cgz_this_error("task tcpWS :{} etype:{} not support", iTask->getName(), (int)etype);
    }
    }
    return true;
}

static int ws_bind(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    const char *name = lua_tostring(L, 1);
    const char *ip = lua_tostring(L, 2);
    int port = lua_tointeger(L, 3);
    int tref = luaL_ref(L, LUA_REGISTRYINDEX);
    void *node = malloc(sizeof(cgzCTcpWS));
    int cid = that->getId();
    auto ctcp = new (node) cgzCTcpWS(that->m_pool, name, ip, port, cid);
    ctcp->m_tref = tref;
    return 0;
}

static int ws_text(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    const char *name = lua_tostring(L, 1);
    const int ufd = lua_tointeger(L, 2);
    const int mid = lua_tointeger(L, 3);
    size_t len = 0;
    const char *pck = lua_tolstring(L, 4, &len);
    int all = len + sizeof(cgzHeader);
    // 添加消息头
    auto buffer = (char *)malloc(all);
    auto &header = *(cgzHeader *)(buffer);
    header.mid = mid;
    header.len = len;
    header.all = all;
    // 拷贝内容
    memcpy(buffer + sizeof(cgzHeader), pck, len);
    void *node = malloc(sizeof(cgzCSendWS));
    auto psend = new (node) cgzCSendWS(ufd, buffer, all, WEBSOCKET_SEND_TEXT);
    that->regTask(name, psend);
    return 0;
}

static int ws_send(lua_State *L)
{
    // 将其转换为 cgzCLua 指针
    cgzCLua *that = cgzCLua::getThat(L);
    const char *name = lua_tostring(L, 1);
    const int ufd = lua_tointeger(L, 2);
    const int mid = lua_tointeger(L, 3);
    size_t len = 0;
    const char *pck = lua_tolstring(L, 4, &len);
    int all = len + sizeof(cgzHeader);
    // 添加消息头
    auto buffer = (char *)malloc(all);
    auto &header = *(cgzHeader *)(buffer);
    header.mid = mid;
    header.len = len;
    header.all = all;
    header.cid = luaL_checkinteger(L, 5);
    // 拷贝内容
    memcpy(buffer + sizeof(cgzHeader), pck, len);
    void *node = malloc(sizeof(cgzCSendWS));
    auto psend = new (node) cgzCSendWS(ufd, buffer, all, WEBSOCKET_SEND_BINARY);
    that->regTask(name, psend);
    free(buffer);
    return 0;
}

int cgzCLua::luaopen_tcpWS(lua_State *L)
{
    static const luaL_Reg otherlib[] = {
        {"bind", ws_bind},
        {"text", ws_text},
        {"send", ws_send},
        {NULL, NULL}};

    luaL_newlib(L, otherlib);
    return 1;
}